﻿
#region 文件信息
/*----------------------------------------------------------------
// 
// 文件名称：	
// 文件功能描述：	
// 设计要求：	
//
// 文 件 名：    RelayCommandGenerator
// 创建者：      杨程
// 创建日期：	    2023/2/6 16:54:01

//----------------------------------------------------------------*/
#endregion

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Text;

namespace Vampirewal.Core.SourceGeneratorMvvm.Generators;

/// <summary>
/// 
/// </summary>
[Generator]
public partial class RelayCommandGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        var syntaxReceiver = (RelayCommandSyntaxReceiver)context.SyntaxReceiver;
        var attributeSyntaxList = syntaxReceiver.CandidateClasses;

        if (attributeSyntaxList.Count == 0)
        {
            return;
        }

        List<string> ClassName = new List<string>();
        foreach (AttributeSyntax attributeSyntax in attributeSyntaxList)
        {
            // 找到class，并且判断一下是否有parital字段
            var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
            {
                continue;
            }

            //判断是否已经处理过这个class了
            if (ClassName.Any(a => a.Equals(classDeclarationSyntax.Identifier.ValueText)))
            {
                continue;
            }

            // 找到namespace
            var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();
            if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText))
            {
                continue;
            }

            // 找到methods
            var methodDeclarationList = classDeclarationSyntax.Members.OfType<MethodDeclarationSyntax>().ToList();
            if (methodDeclarationList.Count == 0)
            {
                continue;
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using Vampirewal.Core.SimpleMVVM;");
            sb.AppendLine();

            sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}");
            sb.AppendLine("{");

            sb.AppendLine($"    public partial class {classDeclarationSyntax.Identifier.Text}");
            sb.AppendLine("    {");

            foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarationList)
            {
                //再判断一下方法上是否标记了RelayCommand特性,没有的话继续，有的话，就正常执行下去
                if (!SyntaxUtils.HasAttribute(methodDeclaration, "RelayCommand"))
                {
                    continue;
                }

                if (methodDeclaration.ParameterList.Parameters.Count > 0)
                {
                    var type = methodDeclaration.ParameterList.Parameters.First();
                    
                    var firstType = type.ToFullString().Split(' ')[0];

                    sb.AppendLine($"private RelayCommand<{firstType}>? _{methodDeclaration.Identifier.Text}Command;");
                    sb.AppendLine($"/// <summary> <see cref=\"{methodDeclaration.Identifier.Text}\"/></summary>");

                    sb.AppendLine($"public RelayCommand<{firstType}> {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand<{firstType}>({methodDeclaration.Identifier.Text});");

                }
                else
                {
                    sb.AppendLine($"        private RelayCommand? _{methodDeclaration.Identifier.Text}Command;");
                    sb.AppendLine($"        /// <summary> <see cref=\"{methodDeclaration.Identifier.Text}\"/></summary>");
                    sb.AppendLine($"        public RelayCommand {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand({methodDeclaration.Identifier.Text});");
                    
                }
            }

            sb.AppendLine("    }");
            sb.AppendLine("}");

            string extensionTextFormatted = CSharpSyntaxTree.ParseText(sb.ToString(), new CSharpParseOptions(LanguageVersion.CSharp8)).GetRoot().NormalizeWhitespace().SyntaxTree.GetText().ToString();
            // 添加到源代码，这样IDE才能感知
            context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", SourceText.From(extensionTextFormatted,Encoding.UTF8));
            // 保存一下类名，避免重复生成
            ClassName.Add(classDeclarationSyntax.Identifier.ValueText);
        }



        //var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions;
        //var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(Utils.GetTemplateByFileName("AttributeTemplate.RelayCommandStr.txt"), options));

        //var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
        //var allAttributes = allNodes.Where((d) => d.IsKind(SyntaxKind.Attribute)).OfType<AttributeSyntax>();
        //var attributes = allAttributes.Where(d => d.Name.ToString() == "RelayCommand").ToList();

        //var allClasses = compilation.SyntaxTrees.SelectMany(x => x.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>());

        ////foreach (var classDeclarationSyntax in allClasses)
        ////{
        ////    context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", "");
        ////}


        //List<string> classList = new List<string>();
        //foreach (AttributeSyntax attributeSyntax in attributes)
        //{
        //    // 找到class，并且判断一下是否有parital字段
        //    var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf<ClassDeclarationSyntax>();
        //    if (classDeclarationSyntax == null ||
        //        !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
        //    {
        //        continue;
        //    }

        //    // 找到namespace
        //    var namespaceDeclarationSyntax =
        //        classDeclarationSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();

        //    if (classList.Contains(classDeclarationSyntax.Identifier.ValueText))
        //    {
        //        continue;
        //    }



        //    //var compilationUnitSyntax = classDeclarationSyntax.SyntaxTree.GetRoot() as CompilationUnitSyntax;
        //    //var usings = compilationUnitSyntax.Usings.Select(m => m.ToString()).ToList();

        //    // 找到method
        //    var methodDeclarationList = classDeclarationSyntax.Members.OfType<MethodDeclarationSyntax>().ToList();
        //    //if (methodDeclarationList.Count == 0)
        //    //{
        //    //    continue;
        //    //}

        //    StringBuilder sb = new StringBuilder();

        //    sb.AppendLine("using Vampirewal.Core.SimpleMVVM;");
        //    sb.AppendLine();

        //    sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}");
        //    sb.AppendLine("{");

        //    sb.AppendLine($"    public partial class {classDeclarationSyntax.Identifier.Text}");
        //    sb.AppendLine("    {");
        //    foreach (var methodDeclaration in methodDeclarationList)
        //    {


        //        //sb.AppendLine($"//该command的参数是{firstType}  12");

        //        if (methodDeclaration.ParameterList.Parameters.Count > 0)
        //        {
        //            var type = methodDeclaration.ParameterList.Parameters.First();
        //            //sb.AppendLine($"//该command的参数是{type.ToFullString()}");

        //            var firstType = type.ToFullString().Split(' ')[0];

        //            sb.AppendLine($"        private RelayCommand<{firstType}>? _{methodDeclaration.Identifier.Text}Command;");

        //            sb.AppendLine();

        //            sb.AppendLine($"        public RelayCommand<{firstType}> {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand<{firstType}>({methodDeclaration.Identifier.Text});");

        //            sb.AppendLine();
        //        }
        //        else
        //        {
        //            sb.AppendLine($"        private RelayCommand? _{methodDeclaration.Identifier.Text}Command;");
        //            sb.AppendLine();
        //            sb.AppendLine($"        public RelayCommand {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand({methodDeclaration.Identifier.Text});");
        //            sb.AppendLine();
        //        }

        //    }



        //    sb.AppendLine("    }");
        //    sb.AppendLine("}");
        //    // 添加到源代码，这样IDE才能感知
        //    context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", sb.ToString());
        //    // 保存一下类名，避免重复生成
        //    classList.Add(classDeclarationSyntax.Identifier.ValueText);
        //}
    }

    public void Initialize(GeneratorInitializationContext context)
    {
#if DEBUG
        //Debugger.Launch();
#endif

        context.RegisterForSyntaxNotifications(() => new RelayCommandSyntaxReceiver());
    }
}

public class RelayCommandSyntaxReceiver : ISyntaxReceiver
{
    public List<AttributeSyntax> CandidateClasses { get; } = new List<AttributeSyntax>();

    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "RelayCommand")
        {
            CandidateClasses.Add(cds);
        }
    }
}

[Generator(LanguageNames.CSharp)]
public class TestGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        //Debugger.Launch();


    }
}
